﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Http;
using System.IO;

namespace ERPStore.Monitor.Services
{
	public class PushHandler : IHandler, IDisposable
	{
		private BufferedMessageSplitter m_MessageSplitter;

		public event Action<string> Received;
		public event Action<AggregateException> Exception;
		public event Action Disconnected;

		public void Start(Models.MonitoredApplication settings, string path, string clientName)
		{
			m_MessageSplitter = new BufferedMessageSplitter(Received);
			var client = new HttpClient();

			// Issue GET request 
			var url = string.Format("{0}/api/{1}", settings.ApiServiceUrl.TrimEnd('/'),path.TrimStart('/'));
			var request = new HttpRequestMessage()
			{
				Method = HttpMethod.Get,
				RequestUri = new Uri(url),
			};
			request.Headers.Add("ApiKey", settings.ApiKey);
			request.Headers.Add("ClientName", clientName);

			client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).ContinueWith((getTask) =>
			{
				if (getTask.IsCanceled)
				{
					return;
				}

				if (getTask.IsFaulted)
				{
					if (Exception != null)
					{
						Exception(getTask.Exception);
					}
					return;
				}
				HttpResponseMessage response = getTask.Result;

				// Get response stream
				response.Content.ReadAsStreamAsync().ContinueWith((streamTask) =>
				{
					if (streamTask.IsCanceled)
					{
						return;
					}

					if (streamTask.IsFaulted)
					{
						if (Exception != null)
						{
							Exception(streamTask.Exception);
						}
						return;
					}

					var readBuffer = new byte[512];
					ReadResponseStream(streamTask.Result, readBuffer);
				});
			});
		}

		private void ReadResponseStream(Stream rspStream, byte[] readBuffer)
		{
			System.Threading.Tasks.Task.Factory.FromAsync<byte[], int, int, int>(rspStream.BeginRead, rspStream.EndRead, readBuffer, 0, readBuffer.Length, state: null).ContinueWith((readTask) =>
			{
				if (readTask.IsCanceled) 
				{
					return;
				}

				if (readTask.IsFaulted)
				{
					if (Exception != null)
					{
						Exception(readTask.Exception);
					}
					return;
				}

				int bytesRead = readTask.Result;
				m_MessageSplitter.Add(readBuffer, bytesRead);

				if (bytesRead != 0)
				{
					ReadResponseStream(rspStream, readBuffer);
				}
				else
				{
					if (Disconnected != null)
					{
						Disconnected();
					}
				}
			});
		}

		public void Stop()
		{
		}

		#region IDisposable Members

		public void Dispose()
		{
			Received = null;
			Exception = null;
			Disconnected = null;
		}

		#endregion
	}
}
